package com.eugeneMa.interceptor;

import com.eugeneMa.util.AuthUtil;
import com.eugeneMa.util.CookieUtil;
import com.eugeneMa.util.StringUtil;
import io.jsonwebtoken.Claims;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.net.URLEncoder;
import java.util.concurrent.TimeUnit;

/**
 * 登录拦截器
 * 保证用户做任何操作均是在登录状态
 *
 * @author Eugenema
 * @date 2022/1/15 17:02
 */
@Component
@PropertySource(value= "classpath:config.properties")
public class LoginInterceptor implements HandlerInterceptor {
    /** 日志 */
    private Logger logger = Logger.getLogger(LoginInterceptor.class);

    /** 本网站地址 */
    @Value("${selfWebUri}")
    private String selfWebUri;

    /** 请求耗时 */
    Long requestUseTime;

    /**
     * 处理器运行之前执行
     * 拦截除登录以外的请求，验证登录信息，将登录信息放入请求域
     *
     * @author Eugenema
     * @date 2022/1/15 17:08
     *
     **/
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {
        try {
            //校验请求来源
            //跳转登录界面及获取验证码请求已过滤，其他请求的来源均需来自本网站，否则跳转到登录界面
            //默认请求，即/请求，转发到登录界面
            String referer = request.getHeader("referer");
            String requestURI = request.getRequestURI();
            if (referer == null || !referer.startsWith(selfWebUri)) {
                logger.error("【来源】：" + referer + "，" + "【请求】：" + requestURI + "，同源网站校验失败，即将跳转到登录界面！");
                request.getRequestDispatcher("/toLoginPage").forward(request, response);
                return false;
            }

            //更改请求编码，防止请求参数中文乱码
            request.setCharacterEncoding("UTF-8");

            //校验是否是AJAX请求
            boolean ajaxFlag = "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));

            //校验登录状态
            String loginInfo = CookieUtil.getCookieValue(request, "loginInfo");
            if (StringUtil.isEmpty(loginInfo)) {
                logger.info("【请求】：" + requestURI + "，用户未登录，即将跳转到登录界面！");
                request.getRequestDispatcher("/static/toTipPage?tipContent=请登录后再操作！&tipType=false&yesUri=/toLoginPage").forward(request, response);
                return false;
            }

            //校验登录信息JWT
            /** 会话域 */
            HttpSession session = request.getSession();
            /** jwt载体信息 */
            Claims payload = null;

            //从会话域中获取jwt的前两部分
            Object jwtString = session.getAttribute(loginInfo);
            if (jwtString == null) {
                logger.error("未找到【" + loginInfo + "】的jwt信息！");
            } else {
                //解析jwt
                payload = AuthUtil.parseJwt(jwtString + "." + loginInfo);
            }

            if (payload == null) {
                logger.error("【请求】：" + requestURI + "，校验登录信息JWT未通过！即将清空cookie和session并跳转提示界面！");
                //删除会话域数据
                session.removeAttribute(loginInfo);
                //删除登录cookie
                CookieUtil.deleteCookie(response, "loginInfo", selfWebUri);
                if (ajaxFlag) {
                    //设置重定向路径
                    response.setHeader("REDIRECT", "REDIRECT");
                    response.setHeader("CONTENTPATH", URLEncoder.encode("/static/toTipPage?tipContent=登录过期，请重新登录！&tipType=false&yesUri=/toLoginPage", "UTF-8"));
                    response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                } else {
                    request.getRequestDispatcher("/static/toTipPage?tipContent=登录过期，请重新登录！&tipType=false&yesUri=/toLoginPage").forward(request, response);
                }
                return false;
            }

            //将登录信息放入请求域
            request.setAttribute("userName", payload.get("userName", String.class));
            request.setAttribute("userId", payload.get("userId"));

            //记录请求开始时间
            requestUseTime = System.currentTimeMillis();
            logger.info("用户ID【" + payload.get("userId") + "】，用户名【" + payload.get("userName", String.class) + "】，请求：【" + requestURI + "】");
            return true;
        } catch (Exception e) {
            logger.error("前置拦截异常！", e);
            return false;
        }
    }

    /**
     * 处理器运行之后执行
     *
     * @author Eugenema
     * @date 2022/1/15 17:08
     *
     * @param
     *
     * @return
     **/
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception {
        //记录请求结束耗时
        Float requestCostTime = (System.currentTimeMillis() - requestUseTime) / 1000f;
        logger.info("用户ID【" + request.getAttribute("userId") + "】，用户名【" + request.getAttribute("userName") + "】，请求：【" + request.getRequestURI() + "】耗时：" + requestCostTime + "秒");
    }

    /**
     * 所有拦截器的后置执行全部结束后，执行该操作
     *
     * @author Eugenema
     * @date 2022/1/15 17:09
     *
     * @param
     *
     * @return
     **/
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
       
    }
}
